package com.zmn.oms.zmn.normal.business.impl.work;

import com.alibaba.fastjson.JSON;
import com.google.common.collect.Lists;
import com.zmn.base.common.data.common.constant.TagConsts;
import com.zmn.base.common.data.common.dro.tags.TagsDRO;
import com.zmn.common.constant.FicoConsts;
import com.zmn.common.constant.GlobalConsts;
import com.zmn.common.dto2.ResponseDTO;
import com.zmn.common.utils.collection.CollectionUtil;
import com.zmn.common.utils.date.DateUtil;
import com.zmn.common.utils.number.NumberUtil;
import com.zmn.common.utils.reflect.BeanMapper;
import com.zmn.common.utils.string.StringUtil;
import com.zmn.consts.GateTypeConsts;
import com.zmn.dms.common.enums.DiscountTypeEnums;
import com.zmn.dms.common.enums.coup.ThirdPlatEnum;
import com.zmn.dms.dubbo.interfaces.coup.coupon.CoupModifyRemoteService;
import com.zmn.manager.mq.constant.MqTopicConsts;
import com.zmn.manager.mq.interfaces.ZmnMQSender;
import com.zmn.manager.redis.RedisManager;
import com.zmn.manager.redis.lock.DistributedLock;
import com.zmn.manager.redis.lock.DistributedLockUtils;
import com.zmn.mos.common.dio.order.add.NormalOrderAddDIO;
import com.zmn.mos.common.dio.order.add.nest.OrderBaseInfo;
import com.zmn.mos.common.dio.order.add.nest.OrderProductDIO;
import com.zmn.mos.common.dio.order.add.nest.UserDIO;
import com.zmn.mos.common.dro.order.OrderAddDRO;
import com.zmn.mos.dubbo.interfaces.order.NormalOrderRemoteService;
import com.zmn.oms.business.interfaces.base.BaseCodeService;
import com.zmn.oms.business.interfaces.changerecord.OrderChangeRecordBService;
import com.zmn.oms.business.interfaces.master.OrderMasterBService;
import com.zmn.oms.business.interfaces.mq.MqProviderService;
import com.zmn.oms.business.interfaces.order.DuplicateOrderBService;
import com.zmn.oms.business.interfaces.orderamount.OrderDiscountCalcBService;
import com.zmn.oms.business.interfaces.orderstock.OrderStockBService;
import com.zmn.oms.business.interfaces.part.OrderPartBService;
import com.zmn.oms.business.interfaces.remark.OrderRemarkBService;
import com.zmn.oms.business.interfaces.track.OrderTrackBService;
import com.zmn.oms.business.interfaces.work.OrderWorkBService;
import com.zmn.oms.business.interfaces.work.orderpay.FactoryAccountModifyBService;
import com.zmn.oms.business.interfaces.xno.OrderXnoBindBService;
import com.zmn.oms.common.annotation.OrderWorkCasOperate;
import com.zmn.oms.common.annotation.ZsNormalOrderWorkLog;
import com.zmn.oms.common.constant.*;
import com.zmn.oms.common.dto.OmsOperator;
import com.zmn.oms.common.enums.OrderWorkCancelEntranceEnum;
import com.zmn.oms.common.enums.RefundInitiateTypeEnum;
import com.zmn.oms.common.exception.OmsBaseException;
import com.zmn.oms.common.utils.TimeUtils;
import com.zmn.oms.common.vo.KVDict;
import com.zmn.oms.constant.MessageQueueTopicConstant;
import com.zmn.oms.manager.utils.OmsMqTagConsts;
import com.zmn.oms.model.bo.refund.RefundInitiateBO;
import com.zmn.oms.model.dto.master.MultiMasterDTO;
import com.zmn.oms.model.dto.order.OrderDTO;
import com.zmn.oms.model.dto.order.zmn.ZsNormalCompensateWorkDTO;
import com.zmn.oms.model.dto.order.zmn.ZsNormalRefundWorkDTO;
import com.zmn.oms.model.dto.orderstock.ReleaseStockDTO;
import com.zmn.oms.model.dto.queue.ErpCancelDTO;
import com.zmn.oms.model.dto.queue.PerfStockWarningDTO;
import com.zmn.oms.model.dto.queue.ScmBackPartDTO;
import com.zmn.oms.model.dto.remark.OrderRemarkDTO;
import com.zmn.oms.model.dto.remark.OrderRemarkDetailDTO;
import com.zmn.oms.model.dto.work.modify.OrderMultipleVisitDTO;
import com.zmn.oms.model.dto.work.modify.must.CancelApplyDTO;
import com.zmn.oms.model.dto.work.modify.must.ZsCancelDTO;
import com.zmn.oms.model.dto.work.xno.XnoUnBindDTO;
import com.zmn.oms.model.entity.conf.cancel.OrderCancelReasonQuery;
import com.zmn.oms.model.entity.detail.OrderDetail;
import com.zmn.oms.model.entity.discount.OrderDiscount;
import com.zmn.oms.model.entity.factory.OrderFactory;
import com.zmn.oms.model.entity.grab.NonGridGrabOrder;
import com.zmn.oms.model.entity.master.OrderMaster;
import com.zmn.oms.model.entity.order.Order;
import com.zmn.oms.model.entity.pay.OrderPay;
import com.zmn.oms.model.entity.product.OrderProduct;
import com.zmn.oms.model.entity.tag.OrderTag;
import com.zmn.oms.model.entity.visit.OrderVisit;
import com.zmn.oms.model.entity.work.OrderWork;
import com.zmn.oms.model.query.grab.NonGridGrabOrderQuery;
import com.zmn.oms.model.vo.conf.cancel.OrderCancelReasonVO;
import com.zmn.oms.model.vo.work.OperatePermissionVO;
import com.zmn.oms.model.vo.work.modify.must.ZsCancelVO;
import com.zmn.oms.model.vo.work.refund.RefundAmountVO;
import com.zmn.oms.services.interfaces.conf.cancel.OrderCancelReasonService;
import com.zmn.oms.services.interfaces.detail.OrderDetailService;
import com.zmn.oms.services.interfaces.discount.OrderDiscountService;
import com.zmn.oms.services.interfaces.factory.OrderFactoryService;
import com.zmn.oms.services.interfaces.fcorderpart.OrderFactoryPartService;
import com.zmn.oms.services.interfaces.grab.NonGridGrabOrderService;
import com.zmn.oms.services.interfaces.master.OrderMasterService;
import com.zmn.oms.services.interfaces.masterworking.MasterWorkingService;
import com.zmn.oms.services.interfaces.order.OrderService;
import com.zmn.oms.services.interfaces.pay.OrderPayService;
import com.zmn.oms.services.interfaces.product.OrderProductService;
import com.zmn.oms.services.interfaces.refund.OrderWorkRefundService;
import com.zmn.oms.services.interfaces.tag.OrderTagService;
import com.zmn.oms.services.interfaces.visit.OrderVisitService;
import com.zmn.oms.services.interfaces.warranty.OrderWarrantyProductService;
import com.zmn.oms.services.interfaces.work.OrderWorkAmountService;
import com.zmn.oms.services.interfaces.work.OrderWorkService;
import com.zmn.oms.zmn.business.interfaces.compensate.CompensateBService;
import com.zmn.oms.zmn.business.interfaces.pay.OrderPayBService;
import com.zmn.oms.zmn.business.interfaces.work.OrderWorkGrabBService;
import com.zmn.oms.zmn.business.interfaces.work.OrderWorkMultipleVisitBService;
import com.zmn.oms.zmn.business.interfaces.work.ZsOrderWorkOperatePermissionBService;
import com.zmn.oms.zmn.business.interfaces.work.customwork.ZsCustomWorkBService;
import com.zmn.oms.zmn.business.interfaces.work.customwork.ZsDistributeWorkBService;
import com.zmn.oms.zmn.business.interfaces.work.orderpay.ZsOrderPayBService;
import com.zmn.oms.zmn.normal.business.interfaces.discount.ZsNormalOrderDiscountBService;
import com.zmn.oms.zmn.normal.business.interfaces.refund.RefundBService;
import com.zmn.oms.zmn.normal.business.interfaces.review.OmsOrderReviewBService;
import com.zmn.oms.zmn.normal.business.interfaces.work.ZsNormalWorkBService;
import com.zmn.pay.common.constant.PayConsts;
import com.zmn.pay.gateway.common.enums.AppEnum;
import com.zmn.pay.gateway.common.model.dio.RevokeGatewayDIO;
import com.zmn.pay.gateway.dubbo.interfaces.pay.PayGatewayRemoteService;
import com.zmn.sp.common.model.manage.SpServProviderDRO;
import com.zmn.sp.dubbo.interfaces.manage.SpManageListRemoteService;
import com.zmn.track.common.constant.TrackConfigConsts;
import com.zmn.track.common.constant.TrackConsts;
import com.zmn.track.common.constant.apply.cancel.CancelApplyConsts;
import com.zmn.track.dubbo.dio.apply.cancel.OrderCancelApplyQuery;
import com.zmn.track.dubbo.dro.apply.cancel.OrderCancelApplyDRO;
import com.zmn.track.dubbo.dto.TrackWorkDIO;
import com.zmn.track.dubbo.dto.TrackWorkDRO;
import com.zmn.track.dubbo.dto.TrackWorkQuery;
import com.zmn.track.dubbo.interfaces.apply.cancel.OrderCancelApplyListRemoteService;
import com.zmn.track.dubbo.interfaces.trackwork.TrackWorkListRemoteService;
import com.zmn.track.dubbo.interfaces.trackwork.TrackWorkModifyRemoteService;
import com.zmn.vas.common.dio.order.OrderCancelDIO;
import com.zmn.vas.common.dro.CheckDRO;
import com.zmn.vas.dubbo.interfaces.order.VasOrderListRemoteService;
import com.zmn.vas.dubbo.interfaces.order.VasOrderManagerModifyRemoteService;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.dubbo.config.annotation.DubboReference;
import org.apache.dubbo.config.annotation.Reference;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 类描述：录入工单业务实现
 *
 * @author liuying
 * @date 2018/11/02 21:02
 */
@Service
public class ZsNormalWorkBServiceImpl implements ZsNormalWorkBService {
    protected Logger logger = LoggerFactory.getLogger(this.getClass());

    private static final List<Long> CONTINUE_CANCEL_REFUNND_ORDER_ID = Lists.newArrayList(
            2758112122403033088L,
            2760557044343259136L,
            2760915845177151489L,
            2761499378094456833L,
            2761626198655635457L,
            2761663873810960385L,
            2761714382307594241L,
            2761747958881325056L,
            2761908598275063808L,
            2761912151295135745L,
            2761962793615233024L,
            2761963369317023745L,
            2761972980950515713L,
            2761983656569880576L,
            2762002391414345728L,
            2762013222906630145L,
            2762064475657342977L,
            2762065283518054400L,
            2762065477181652992L,
            2762074938474512384L,
            2762077655704027136L,
            2762083707329724417L,
            2762181199983558657L,
            2762181199987752960L,
            2766991521093259265L

    );

   // @Reference(version = com.zmn.base.engineer.common.constants.DubboConsts.INTERFACE_VERSION, check = false)
   // private EngineerTouchModifyRemoteService engineerTouchModifyRemoteService;

    @Autowired
    private MqProviderService mqProviderService;

    @Reference(version = com.zmn.vas.dubbo.consts.VasDubboConsts.INTERFACE_VERSION, check = false)
    private VasOrderManagerModifyRemoteService vasOrderManagerModifyRemoteService;
    @Reference(version = com.zmn.vas.dubbo.consts.VasDubboConsts.INTERFACE_VERSION, check = false)
    private VasOrderListRemoteService vasOrderListRemoteService;
    @Reference(version = com.zmn.base.plat.engine.common.constant.DubboConsts.INTERFACE_VERSION , check = false)
    private SpManageListRemoteService spManageListRemoteService;
    @Reference(version = com.zmn.base.engineer.common.constants.DubboConsts.INTERFACE_VERSION, check = false)
    private PayGatewayRemoteService payGatewayRemoteService;
    //@Reference(version = com.zmn.base.engineer.common.constants.DubboConsts.INTERFACE_VERSION, check = false)
    //private TouchModifyRemoteService touchModifyRemoteService;
    @Reference(version = com.zmn.track.dubbo.consts.DubboConsts.INTERFACE_VERSION, check = false)
    private TrackWorkModifyRemoteService trackWorkModifyRemoteService;
    @Reference(version = com.zmn.track.dubbo.consts.DubboConsts.INTERFACE_VERSION, check = false)
    private CoupModifyRemoteService coupModifyRemoteService;
    @DubboReference(version = com.zmn.mos.dubbo.utils.DubboConsts.INTERFACE_VERSION, timeout = 10000, check = false)
    private NormalOrderRemoteService normalOrderRemoteService;
    @Reference(version = com.zmn.track.dubbo.consts.DubboConsts.INTERFACE_VERSION, check = false)
    private OrderCancelApplyListRemoteService orderCancelApplyListRemoteService;
    @DubboReference(version = com.zmn.track.dubbo.consts.DubboConsts.INTERFACE_VERSION, check = false)
    private TrackWorkListRemoteService trackWorkListRemoteService;

    @Autowired
    private ZsCustomWorkBService zsCustomWorkBService;
    @Autowired
    private FactoryAccountModifyBService factoryAccountModifyBService;

    @Autowired
    private OrderWorkBService orderWorkBService;
    @Autowired
    private OrderVisitService orderVisitService;
    @Autowired
    private OrderWorkMultipleVisitBService orderWorkMultipleVisitBService;
    @Autowired
    private OrderService orderService;
    @Autowired
    private OrderWorkService orderWorkService;
    @Autowired
    private OrderDetailService orderDetailService;
    @Autowired
    private OrderPartBService orderPartBService;
    @Autowired
    private OrderRemarkBService orderRemarkBService;
    @Autowired
    private OrderMasterBService orderMasterBService;
    @Autowired
    private OrderWorkRefundService orderWorkRefundService;
    @Autowired
    private OrderFactoryService orderFactoryService;
    @Autowired
    private ZsOrderPayBService zsOrderPayBService;
    @Autowired
    private BaseCodeService baseCodeService;
    @Autowired
    private MasterWorkingService masterWorkingService;
    @Autowired
    private ZsOrderWorkOperatePermissionBService zsOrderWorkOperatePermissionBService;
    @Autowired
    private OrderFactoryPartService orderFactoryPartService;
    @Autowired
    private RefundBService refundBService;
    @Autowired
    private CompensateBService compensateBService;
    @Autowired
    private OrderPayBService orderPayBService;
    @Autowired
    private OrderXnoBindBService orderXnoBindBService;
    @Autowired
    private OrderTrackBService orderTrackBService;
    @Autowired
    private OrderDiscountService orderDiscountService;
    @Autowired
    private OrderDiscountCalcBService orderDiscountCalcBService;
    @Autowired
    private OrderWarrantyProductService orderWarrantyProductService;
    @Autowired
    private ZsNormalOrderDiscountBService zsNormalOrderDiscountBService;
    @Autowired
    private DuplicateOrderBService duplicateOrderBService;
    @Autowired
    private OrderPayService orderPayService;
    @Autowired
    private OrderWorkGrabBService orderWorkGrabBService;
    @Autowired
    private NonGridGrabOrderService nonGridGrabOrderService;
    @Resource
    private ZmnMQSender zmnMQSender;
    @Autowired
    private RedisManager redisManager;
    @Autowired
    private OrderMasterService orderMasterService;
    @Autowired
    private OrderWorkAmountService orderWorkAmountService;
    @Autowired
    private OrderStockBService orderStockBService;
    @Autowired
    private OrderChangeRecordBService orderChangeRecordBService;
    @Autowired
    private OmsOrderReviewBService omsOrderReviewBService;
    @Resource
    private OrderCancelReasonService orderCancelReasonService;
    @Autowired
    private ZsDistributeWorkBService zsDistributeWorkBService;
    @Autowired
    private OrderProductService orderProductService;
    @Autowired
    private OrderTagService orderTagService;

    // 不调用资金帐号的订单（临时）
    private List<String> tempWorkIds = Arrays.asList(
			"498879555658854400","498946626635702272","498946628388921344","499237312098476032","499654197570973696","499654265258651648","499654266235924480","499658595571343360","499658597391671296","499658628471463936","500001744634261504","500001745569591296","500399872147464192","500399873103765504","500399874181701632","500399942162980864","500401555636236288","500401557540450304","500801434959228928","501402010893950976","501438428420775936","501438429456769024","501438465519394816","517671549373784064","498879553695920128","498879554664804352","498946623993290752","498946624848928768","498946631018749952","499237280859299840","499237308524929024","499237314929631232","499654200834142208","499654236359897088","499658633320079360","500002712276971520","500399939256328192","500399944113332224","500401552746360832","500401559364972544","501401146888298496","502789493569368064","498879549858131968","498879550810238976","498944986352463872","498946634441302016","499237302690652160","499237303617593344","499653742761619456","499654204428660736","499654224913641472","500001686073389056","500399898819043328","500702933722079232","501401156652638208","501401157650882560","501402017604837376","501402036235935744","501438422364200960","501438437832794112","501438458091282432","498879544917241856","498944989691129856","498944991414988800","498949777736605696","499237298819309568","499237299821748224","499237323339210752","499237333762056192","499654209860284416","499654243129503744","499654244048056320","499654254672228352","499658583118454784","499658608632406016","499658617981509632","499658618904256512","500001701336461312","500001723947954176","500002754513612800","500401533930713088","500800255277674496","501401172536467456","501401173530517504","501438452483497984","498879540823601152","498879541859594240","499237292418801664","499237295090573312","499654213639352320","500001762116120576","500001764796280832","500002760620519424","500399888333283328","500399890241691648","500399891177021440","500399892120739840","500399925721309184","500800247920865280","500801450805309440","501401168581238784","501438413753294848","501438447064457216","498879542874615808","498879543906414592","498944992266432512","498949773911400448","499237291366031360","499249420185903104","499602946774806528","499653737166417920","499658582166347776","500001767489024000","500401542407401472","501401136427704320","501401163518713856","501438409076645888","501438444317188096","501438450696724480","501439406595383296","501691545242578944","546722180453376000","498879546884370432","498879547857448960","498879548851499008","498944988848074752","498949779603070976","499237301780488192","499654242177396736","499654256614191104","499658585957998592","499658620812664832","500001755791110144","500002718048333824","500002734255124480","500399897896296448","500800256280113152","500801426604175360","501401141125324800","501401159500570624","501402018611470336","501438420485152768","525739654230581248","554059230433259521","498879551737180160","498879552743813120","498946622198128640","499237316720599040","499654237408473088","499658566316072960","500001718222729216","500002713157775360","500399913490718720","500399935552757760","500401551832002560","500800272755339264","500801439581351936","500801463866372096","501323020674019328","501438435962134528","501439420692439040","501439421535494144","501439422500184064"    );

    @Override
    public ZsCancelVO getCancelVO(Long orderId, Long workId) {

        OrderWork orderWork = orderWorkService.findOrderWorkByKey(orderId, workId);

        ZsCancelVO cancelVO = new ZsCancelVO();
        cancelVO.setOrderWork(orderWork);
        cancelVO.setDuplicateMapId(String.valueOf(OrderConsts.CANCEL_DUPLICATE_ID));

        // 工单有内采配件/外报/订单杂项费用
        Integer inSourcingAmount = orderWork.getInSourcingAmount();
        Integer outSourcingAmount = orderWork.getOutSourcingAmount();
        Integer deliverAmount = orderWork.getDeliverAmount();
        if (!NumberUtil.isNullOrZero(inSourcingAmount)
                || !NumberUtil.isNullOrZero(outSourcingAmount)
                || !NumberUtil.isNullOrZero(deliverAmount)) {
            cancelVO.setPart(true);
        } else {
            cancelVO.setPart(false);
        }

        // 工单有待审核的厂商配件
        cancelVO.setFactoryPart(false);
        if (Objects.equals(orderWork.getBizType(), com.zmn.consts.GlobalConsts.BIZ_TYPE_F)
                && !NumberUtil.isNullOrZero(orderWork.getFactoryPartAmount())) {
            cancelVO.setFactoryPart(true);
        }

        // 取消缘由（根据：服务平台、订单节点、类型：后台、状态：启用）
        List<KVDict<Integer>> cancelList = Lists.newArrayList();
        OrderCancelReasonQuery orderCancelReasonQuery = new OrderCancelReasonQuery();
        orderCancelReasonQuery.setBizType(orderWork.getBizType());
        orderCancelReasonQuery.setType(1);
        orderCancelReasonQuery.setStatus(GlobalConsts.YES);
        // 未派单取消：已录入/已确认/已分单-进行中
        List<Integer> undistributedList = Lists.newArrayList(OrderStatusConsts.WORK_STATUS_INPUT, OrderStatusConsts.WORK_STATUS_CONFIRM, OrderStatusConsts.WORK_STATUS_ASSIGN);
        // 未上门取消：已派单/已领单-进行中
        List<Integer> unvisitedList = Lists.newArrayList(OrderStatusConsts.WORK_STATUS_DISTRIBUTE, OrderStatusConsts.WORK_STATUS_TAKE);
        // 已上门取消：已上门-进行中
        List<Integer> visitedList = Lists.newArrayList(OrderStatusConsts.WORK_STATUS_VISIT);
        Integer status = orderWork.getStatus();
        Integer resultStatus = orderWork.getResultStatus();
        Integer node = 0;
        // 取消节点 1 未派单取消、2 未上门取消、3 已上门取消
        if (Objects.equals(resultStatus, 1)) {
            if (undistributedList.contains(status)) {
                node = GlobalConsts.LEVEL_1;
            } else if (unvisitedList.contains(status)) {
                node = GlobalConsts.LEVEL_2;
            } else if (visitedList.contains(status)) {
                node = GlobalConsts.LEVEL_3;
            }
        }
        orderCancelReasonQuery.setNode(node);
        List<OrderCancelReasonVO> orderCancelReasonVOList = orderCancelReasonService.listByQuery(orderCancelReasonQuery);
        orderCancelReasonVOList.stream().sorted(Comparator.comparing(OrderCancelReasonVO::getId)).forEach( e -> {
                    cancelList.add(KVDict.<Integer>builder().value(e.getId()).text(e.getReason()).pidText(e.getCategName()).ext1(e.getRemark()).build());
                });

        // 处理重复工单ID
        Long duplicateOrderId = duplicateOrderBService.findDuplicateOrderId(orderWork);
        if (NumberUtil.isNotNullOrZero(duplicateOrderId)) {
            cancelVO.setDuplicateOrderId(duplicateOrderId);
            cancelList.stream().filter(reason -> {
                return Objects.equals(reason.getValue(), OrderConsts.CANCEL_DUPLICATE_ID);
            }).findFirst().ifPresent(reason -> {
                reason.setSelected(true);
            });
            // 只能选择重复
            for (KVDict<Integer> integerKVDict : cancelList) {
                integerKVDict.setDisabled(true);
            }

        } else {
            // 如果没有重复工单，取消重复这一项缘由
            cancelList.removeIf(reason -> {
                return Objects.equals(reason.getValue(), OrderConsts.CANCEL_DUPLICATE_ID);
            });
        }

        // 审核状态
        KVDict<Integer> passReview = KVDict.<Integer>builder()
                .value(OrderConsts.REVIEW_STATUS_SUCCESS)
                .text("通过").selected(true).build();
        KVDict<Integer> unPassReview = KVDict.<Integer>builder()
                .value(OrderConsts.REVIEW_STATUS_FAIL)
                .text("不通过").build();
        cancelVO.setReviewList(Lists.newArrayList(passReview, unPassReview));
        Map<String, List<KVDict<Integer>>> resultMap = cancelList.stream().collect(Collectors.groupingBy(KVDict::getPidText));
        cancelVO.setCancelList(resultMap);

        // 平台直子公司查询家修匠可服务工程师，api接口除外
        // 没师傅才查询家修匠工程师
        if (Objects.equals(orderWork.getDistributeWay(), OrderDistributeConsts.DISTRIBUTE_WAY_PLAT)
                && !Objects.equals(orderWork.getInputType(), OrderConsts.ORDER_INPUT_TYPE_API)
                && NumberUtil.isNullOrZero(orderWork.getMasterId())) {
            OrderDetail orderDetail = orderDetailService.findOrderDetailByKey(orderWork.getOrderId());
            // 行政子公司不是家修匠才查询
            if (!Objects.equals(orderDetail.getGridCompanyId(), CompanyConsts.ZMN_JXJ_COMPANY_ID)) {
                Integer count = zsDistributeWorkBService.countJXJAvailableMaster(orderWork, orderDetail);
                cancelVO.setJxjEngineerCount(count);
            }
        }

        TrackWorkQuery query = new TrackWorkQuery();
        query.setOrderId(orderId);
        query.setWorkId(workId);
        query.setTrackContentIdList(Lists.newArrayList(TrackConfigConsts.TRACK_CONTENT_ID_SUSPECTED_REPEATED));
        query.setNotStatus(TrackConsts.TRACK_STATUS_FINISHED);
        ResponseDTO<List<TrackWorkDRO>> listResponseDTO = trackWorkListRemoteService.listTrackByQuery(query);
        cancelVO.setSuspectedDuplicateOrder(Boolean.FALSE);
        if (Objects.nonNull(listResponseDTO) && CollectionUtil.isNotNullOrEmpty(listResponseDTO.getData())) {
            cancelVO.setSuspectedDuplicateOrder(Boolean.TRUE);
        }
        return cancelVO;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @OrderWorkCasOperate(type = OrderConsts.ORDER_OP_TYPE_CANCEL)
    @ZsNormalOrderWorkLog(type = OrderLogConsts.ORDER_LOG_TYPE_CANCEL, beforeProceed = false)
    public void saveCancel(ZsCancelDTO zsCancelDTO) throws OmsBaseException {

        String lockKey = String.format("%s_%s", zsCancelDTO.getOrderId(), zsCancelDTO.getWorkId());
        DistributedLock lock = DistributedLockUtils.build(LockConsts.LOCK_ORDER_CANCEL_FORMAT + lockKey, LockConsts.LOCK_VALID_TIME);
        try {
            if (lock.tryLock()) {

                // 取消校验
                this.cancelVerify(zsCancelDTO);

                // 处理用户端缘由映射
                this.userReasonMapping(zsCancelDTO);
                // 查询工单
                OrderWork dbOrderWork = orderWorkService.findOrderWorkByKeySrcMaster(zsCancelDTO.getOrderId(), zsCancelDTO.getWorkId());
                if (Objects.isNull(dbOrderWork)) {
                    throw new OmsBaseException(OmsErrorCodeConsts.ORDER_NOT_FOUND, "工单不存在");
                }
                // 退款单取消
                boolean isRefundOrder = Objects.equals(dbOrderWork.getType(), OrderConsts.ORDER_TYPE_REFUND);
                if (isRefundOrder) {
                    zsCancelDTO.setResultStatus(OrderStatusConsts.WORK_RESULT_DISCARD);
                    refundBService.refundOrderCancel(dbOrderWork, zsCancelDTO);
                    return;
                }

                // 赔偿单取消
                boolean isCompensateOrder = Objects.equals(dbOrderWork.getType(), OrderConsts.ORDER_TYPE_COMPENSATE);
                if (isCompensateOrder) {
                    compensateBService.cancelCompensateOrder(dbOrderWork, zsCancelDTO);
                    return;
                }

                // 退款取消
                boolean refundCancel = Objects.equals(zsCancelDTO.getRefundCancel(), GlobalConsts.YES);

                Integer resultStatus = dbOrderWork.getResultStatus();
                if (!Objects.equals(resultStatus, OrderStatusConsts.WORK_RESULT_DOING)) {
                    throw new OmsBaseException(OmsErrorCodeConsts.ERROR_ORDER_CANCEL_STATUS, "取消失败，订单不处于进行中状态。");
                }

                // 处理重复单信息
                if (NumberUtil.isNullOrZero(zsCancelDTO.getOriginalCode())) {
                    Long duplicateOrderId = duplicateOrderBService.findDuplicateOrderId(dbOrderWork);
                    // 有重复单
                    if (NumberUtil.isNotNullOrZero(duplicateOrderId)) {
                        // 设置原单ID
                        zsCancelDTO.setOriginalCode(duplicateOrderId);

                        List<OrderRemarkDetailDTO> remarkDetailDTOS = Optional.ofNullable(zsCancelDTO.getDetailDTOList()).orElse(Lists.newArrayList());
                        OrderRemarkDetailDTO detail = new OrderRemarkDetailDTO();
                        detail.setMapId(OrderConsts.CANCEL_DUPLICATE_ID);
                        detail.setMapName("重复");
                        remarkDetailDTOS.add(detail);
                        zsCancelDTO.setDetailDTOList(remarkDetailDTOS);
                    }
                }

                Integer status = dbOrderWork.getStatus();
                // 派单后取消，解绑小号 -》延迟到7天后解绑
                OrderDetail orderDetail = orderDetailService.findOrderDetailByKey(zsCancelDTO.getOrderId());
                if (status > OrderStatusConsts.WORK_STATUS_ASSIGN) {
                    XnoUnBindDTO xnoUnBindDTO = new XnoUnBindDTO();
                    xnoUnBindDTO.setOrderId(dbOrderWork.getOrderId());
                    xnoUnBindDTO.setWorkId(dbOrderWork.getWorkId());
                    orderXnoBindBService.sendToUnBindQueue(xnoUnBindDTO);
                }

                OrderWork updateOrderWork = new OrderWork();
                updateOrderWork.setOrderId(zsCancelDTO.getOrderId());
                updateOrderWork.setWorkId(zsCancelDTO.getWorkId());
                updateOrderWork.setResultTime(DateUtil.getNow());
                updateOrderWork.setResulterId(zsCancelDTO.getOperatorId());
                updateOrderWork.setResulterType(zsCancelDTO.getOperatorType());
                if (CollectionUtil.isNotNullOrEmpty(zsCancelDTO.getDetailDTOList())) {
                    boolean isTest = zsCancelDTO.getDetailDTOList().stream().anyMatch(detail -> {
                        return Objects.equals(detail.getMapId(), OrderConsts.CANCEL_TEST_ID);
                    });
                    if (isTest) {
                        updateOrderWork.setTest(GlobalConsts.YES);
                    }
                }
                // A. 已录入&已确认&已分单&已接单-进行中，塞结果：弃单
                List<Integer> supportAStatusList = Arrays.asList(OrderStatusConsts.WORK_STATUS_INPUT, OrderStatusConsts.WORK_STATUS_CONFIRM, OrderStatusConsts.WORK_STATUS_ASSIGN);
                if (supportAStatusList.contains(status)) {
                    updateOrderWork.setResultStatus(OrderStatusConsts.WORK_RESULT_DISCARD);
                    zsCancelDTO.setResultStatus(OrderStatusConsts.WORK_RESULT_DISCARD);
                }

                // B.已派单&已领单&已上门-进行中，塞结果：失败
                List<Integer> supportBStatusList = Arrays.asList(OrderStatusConsts.WORK_STATUS_VISIT, OrderStatusConsts.WORK_STATUS_TAKE, OrderStatusConsts.WORK_STATUS_DISTRIBUTE);
                if (supportBStatusList.contains(status)) {
                    updateOrderWork.setResultStatus(OrderStatusConsts.WORK_RESULT_FAIL);
                    zsCancelDTO.setResultStatus(OrderStatusConsts.WORK_RESULT_FAIL);
                }

                // C.若有渠道预付，塞：退款额， -- 支付状态塞：已退款
                if (!refundCancel) {
                    if (!NumberUtil.isNullOrZero(dbOrderWork.getChannelPrepayAmount())) {
                        Integer channelPrepayAmount = dbOrderWork.getChannelPrepayAmount();

                        if (Objects.equals(dbOrderWork.getChannelPrepayStatus(), PayConsts.PAY_STATUS_ING)) {

                            // 支付中，设置为未支付
                            updateOrderWork.setChannelPrepayStatus(PayConsts.REFUND_STATUS_DONE);
                            updateOrderWork.setPayStatus(PayConsts.REFUND_STATUS_DONE);
                        } else if (Objects.equals(dbOrderWork.getChannelPrepayStatus(), PayConsts.PAY_STATUS_DONE)) {

                            // 已支付，自动退款
                            updateOrderWork.setRefundAmount(channelPrepayAmount);
                            updateOrderWork.setChannelPrepayStatus(PayConsts.REFUND_STATUS_DONE);
                            updateOrderWork.setPayStatus(PayConsts.REFUND_STATUS_DONE);

                            orderWorkRefundService.insertOrderWorkRefund(zsCancelDTO.getOrderId(), zsCancelDTO.getWorkId(), channelPrepayAmount, FicoConsts.ORDER_IN_CHANNEL_PREPAY, GlobalConsts.YES);
                        }
                    }

                    // 若有啄木鸟预付
                    if (!NumberUtil.isNullOrZero(dbOrderWork.getPrepayAmount())) {
                        if (Objects.equals(dbOrderWork.getPrepayStatus(), PayConsts.PAY_STATUS_ING)) {
                            // 支付中，设置为未支付
                            updateOrderWork.setPrepayStatus(PayConsts.PAY_STATUS_NONE);
                            updateOrderWork.setPayStatus(PayConsts.PAY_STATUS_NONE);
                        }
                    }
                }

                // D.若有：内采配件、外报、订单杂项费用，则相应清空 (clearOrderPart by heciqi)
                orderPartBService.clearOmsOrderPart(zsCancelDTO.getOrderId());

                // orderPartBService.clearOrderPart(zsCancelDTO.getOrderId(), zsCancelDTO.getOperatorId(),
                //         zsCancelDTO.getOperator());

                // 会员单 迁移至 增值服务 所以不需要调用ums接口
    //        boolean isMember = Objects.equals(GlobalConsts.YES, dbOrderWork.getMember());
    //        // E.会员单，取消后，需返还会员权益
    //        if (isMember) {
    //            com.zmn.common.dto2.ResponseDTO<Boolean> responseDTO = memberModifyRemoteService.returnUseEquityByUserIdAndServorderId(dbOrderWork.getUserId(), dbOrderWork.getOrderId());
    //            logger.info("退还权益： 订单ID={}，用户ID={}，结果：{}", dbOrderWork.getOrderId(), dbOrderWork.getUserId(), responseDTO);
    //        }

                // F.若有厂商配件，则取消后将清空数据
                orderFactoryPartService.deleteByOrderId(zsCancelDTO.getOrderId());

                // 有重复单
                Long originalCode = zsCancelDTO.getOriginalCode();
                if (originalCode != null) {
                    updateOrderWork.setOriginalId(originalCode);
                    updateOrderWork.setDuplicateId(originalCode);
                    updateOrderWork.setDuplicate(GlobalConsts.YES);
                }

                // 设置取消人信息
                updateOrderWork.setCancelerId(zsCancelDTO.getOperatorId());
                updateOrderWork.setCancelerType(zsCancelDTO.getOperatorType());
                updateOrderWork.setCancelTime(DateUtil.getNow());

                // 判断手机号是否为17777777777 或者 下单备注为啄木鸟测试
                String telephone = "17777777777";
                String remark = "啄木鸟测试";
                if (orderDetail != null && (Objects.equals(orderDetail.getTelephone(), telephone) || Objects.equals(orderDetail.getRemark(), remark))) {
                    updateOrderWork.setDuplicate(GlobalConsts.YES);
                }
                // 修改字段 resultStatus originalId refundAmount prepayStatus channelPrepayStatus payStatus resultTime resulterId appliqueStatus
                orderWorkService.updateCancel(updateOrderWork);

                // 保存工单取消备注
                if (!refundCancel) {
                    orderRemarkBService.insertOrderRemark(zsCancelDTO, OrderConsts.ORDER_REMARK_TYPE_CANCEL);
                }

                // 删除进行中工单并清除师傅工单版本号
                boolean deleted = masterWorkingService.deleteMasterWorking(zsCancelDTO.getWorkId());
                if (deleted) {
                    //engineerTouchModifyRemoteService.saveEngineerWorkVersion(dbOrderWork.getMasterId(), null);
                    mqProviderService.sendEngineerWorkVersion(dbOrderWork.getMasterId(), null);
                }

                // 厂商保内单取消时 解冻冻结金额
                boolean isFactoryOrder = Objects.equals(dbOrderWork.getSourceType(), OrderConsts.ORDER_SOURCE_TYPE_FACTORY);
                boolean containsTempWorkId = tempWorkIds.contains(String.valueOf(dbOrderWork.getWorkId()));
                if (!containsTempWorkId && isFactoryOrder && Objects.equals(dbOrderWork.getBizType(), com.zmn.consts.GlobalConsts.BIZ_TYPE_F)) {
                    OrderFactory orderFactory = orderFactoryService.findOrderFactoryByKey(dbOrderWork.getOrderId());
                    factoryAccountModifyBService.unFreeze(dbOrderWork, orderFactory, zsCancelDTO);
                }

                Long orderId = dbOrderWork.getOrderId();
                if (NumberUtil.isNotNullOrZero(dbOrderWork.getDiscountAmount())) {
                    List<OrderDiscount> orderDiscountList = orderDiscountService.listByOrderId(orderId);
                    if (CollectionUtil.isNotNullOrEmpty(orderDiscountList)) {
                        // 师傅未上门取消订单或退款取消-退还优惠券
                        if (status < OrderStatusConsts.WORK_STATUS_VISIT || refundCancel || Objects.equals(dbOrderWork.getMember(), GlobalConsts.YES)) {
                            // 非渠道和全免优惠退回
                            List<OrderDiscount> backDiscountList = orderDiscountList.stream()
                                    .filter(e -> !(Objects.equals(e.getCateg(), DiscountConsts.DISCOUNT_CATEG_CHANNEL)
                                            || Objects.equals(e.getCateg(), DiscountTypeEnums.DISCOUNT_COUP_ONCECARD.getSubType())
                                            || Objects.equals(e.getSourceId(), DiscountConsts.BATCH_ID_FREE_DISCOUNT_HQ_COMPANY)
                                            || Objects.equals(e.getSourceId(), DiscountConsts.BATCH_ID_FREE_DISCOUNT_SUB_COMPANY)))
                                    .collect(Collectors.toList());
                            orderDiscountCalcBService.backDiscount(backDiscountList);
                        }
                        // 渠道和特殊优惠作废，美团优惠券也作废
                        List<OrderDiscount> obsDiscountList = orderDiscountList.stream()
                                .filter(e -> Objects.equals(e.getCateg(), DiscountConsts.DISCOUNT_CATEG_CHANNEL)
                                        || Objects.equals(e.getSourceId(), DiscountConsts.BATCH_ID_FREE_DISCOUNT_HQ_COMPANY)
                                        || Objects.equals(e.getSourceId(), DiscountConsts.BATCH_ID_FREE_DISCOUNT_SUB_COMPANY)
                                        || (Objects.equals(e.getThirdCode(), com.zmn.consts.GlobalConsts.NO)
                                        && Objects.equals(e.getThirdCoupPlat(), ThirdPlatEnum.THIRD_COUP_TYPE_MT.getKey())))
                                .collect(Collectors.toList());
                        orderDiscountCalcBService.obsDiscount(obsDiscountList);
                        // 清除redis中缓存的特殊优惠券
                        orderDiscountCalcBService.delRedisSpecialDiscountCoupon(orderId);

                        // 次卡逻辑处理
                        List<OrderDiscount> backDiscountList = orderDiscountList.stream()
                                .filter(e -> Objects.equals(e.getCateg(), DiscountTypeEnums.DISCOUNT_COUP_ONCECARD.getSubType()))
                                .collect(Collectors.toList());
                        if (CollectionUtils.isNotEmpty(backDiscountList)) {
                            if (dbOrderWork.getStatus() < OrderStatusConsts.WORK_STATUS_SERVICE_COMPLETE) {
                                // 退还卡券
                                orderDiscountCalcBService.backDiscount(backDiscountList);
                            } else {
                                // 退款
                                zsOrderPayBService.timesCardRefund(dbOrderWork.getOrderId(), dbOrderWork.getWorkId(),
                                        backDiscountList.get(0).getItemCode(), dbOrderWork.getDiscountPrepayAmount(),
                                        OrderConsts.ORDER_REFUND_TYPE_ONLINE, zsCancelDTO);
                            }
                            if (NumberUtil.isNullOrZero(dbOrderWork.getDiscountPrepayAmount())) {
                                {
                                    logger.error(String.format("订单[{}]有次卡优惠券,但是优惠支付金额为[%s]", dbOrderWork.getWorkId(), dbOrderWork.getDiscountPrepayAmount()));
                                }
                            }

                        }
                    }
                } else {
                    // 作废优惠券
                    String redisItemCodeKey = String.format(RedisKeyConsts.DISCOUNT_SPECIAL_ITEMCODE_KEY, dbOrderWork.getOrderId());
                    if (redisManager.exists(redisItemCodeKey)) {
                        orderDiscountCalcBService.obsDiscountItemCodes(Lists.newArrayList(redisManager.get(redisItemCodeKey)),dbOrderWork.getOrderId());
                        orderDiscountCalcBService.delRedisSpecialDiscountCoupon(orderId);
                    }
                }

                // 删除优惠信息及报价标示
                zsNormalOrderDiscountBService.deleteOrderMasterApplyDiscountAndQuotation(dbOrderWork.getWorkId(), dbOrderWork.getMasterId());

                // 查询是否有对应的增值服务订单
                try {
                    ResponseDTO<CheckDRO> checkDROResponseDTO = vasOrderListRemoteService.isExistByWorkId(dbOrderWork.getWorkId());
                    if (checkDROResponseDTO.isSuccess() && Objects.equals(checkDROResponseDTO.getData().getResult(), GlobalConsts.YES)) {
                        Long vasOrderId = checkDROResponseDTO.getData().getOrderId();
                        String cancelContent = "维保订单取消";

                        OrderCancelDIO orderCancelDIO = new OrderCancelDIO();
                        orderCancelDIO.setOperatorId(zsCancelDTO.getOperatorId());
                        orderCancelDIO.setOperatorType(zsCancelDTO.getOperatorType());
                        orderCancelDIO.setOperator(zsCancelDTO.getOperator());
                        orderCancelDIO.setOrderId(vasOrderId);
                        orderCancelDIO.setContent(cancelContent);

                        vasOrderManagerModifyRemoteService.cancel(orderCancelDIO);
                    }
                } catch (Exception e) {
                    logger.info("[{}]取消增值订单失败 error:{}", orderId, e);
                }

                // 取消后，自动完成跟单
                orderTrackBService.completeAllTrack(dbOrderWork.getOrderId(), dbOrderWork.getWorkId(), "工单取消");

                // 如果正在抢单则将订单从抢单池移除
                if (Objects.equals(dbOrderWork.getGrabType(), GlobalConsts.YES)) {
                    // 判断订单是否属于无网格抢单
                    NonGridGrabOrderQuery query = new NonGridGrabOrderQuery();
                    query.setOrderId(dbOrderWork.getOrderId());
                    query.setWorkId(dbOrderWork.getWorkId());
                    query.setValidStatus(com.zmn.consts.GlobalConsts.YES);
                    List<NonGridGrabOrder> nonGridGrabOrderList = nonGridGrabOrderService.listByQuery(query);
                    if (CollectionUtil.isNotNullOrEmpty(nonGridGrabOrderList)) {
                        NonGridGrabOrder nonGridGrabOrder = new NonGridGrabOrder();
                        nonGridGrabOrder.setOrderId(zsCancelDTO.getOrderId());
                        nonGridGrabOrder.setWorkId(zsCancelDTO.getWorkId());
                        nonGridGrabOrder.setValidStatus(com.zmn.consts.GlobalConsts.NO);
                        nonGridGrabOrderService.updateByKey(nonGridGrabOrder);
                    } else {
                        orderWorkGrabBService.deleteGrabOrderWithLock(dbOrderWork.getWorkId());
                    }
                }

                if (Objects.nonNull(zsCancelDTO.getReviewStatus())) {
                    // 更新审核状态
                    OrderWork upOrderWork = new OrderWork();
                    upOrderWork.setOrderId(zsCancelDTO.getOrderId());
                    upOrderWork.setWorkId(zsCancelDTO.getWorkId());
                    upOrderWork.setRefundReviewStatus(zsCancelDTO.getReviewStatus());
                    orderWorkAmountService.updateRefund(upOrderWork);
                    // 更新masterWorking.waitCancel
                    masterWorkingService.updateMasterWorkingStatus(zsCancelDTO.getWorkId(), null, null, GlobalConsts.NO);
                }

                // 释放库存
                ReleaseStockDTO releaseStockDTO = new ReleaseStockDTO();
                releaseStockDTO.setOrderId(dbOrderWork.getOrderId());
                releaseStockDTO.setWorkId(dbOrderWork.getWorkId());
                releaseStockDTO.setMasterId(dbOrderWork.getMasterId());
                releaseStockDTO.setCityId(dbOrderWork.getCityId());
                orderStockBService.releaseStock(releaseStockDTO);

                // 调用支付网关，尝试取消正在支付中的订单
                try {
                    this.cancelPayOrder(dbOrderWork, zsCancelDTO);
                } catch (OmsBaseException oe) {
                    logger.info("[{}]取消进行中的支付订单失败", orderId);
                }

                // 返修单不处理
                //if (!Objects.equals(dbOrderWork.getType(), OrderConsts.ORDER_TYPE_REWORK)) {
                // 取消时设置责任工程师
                orderChangeRecordBService.updateCancelLiableMasterRecord(zsCancelDTO.getOrderId(), zsCancelDTO.getWorkId());
                //}

                // 退还订单下单时发放的优惠券
                ResponseDTO<Integer> coupResponseDTO = coupModifyRemoteService.systemInvalidCouponsByOrderId(orderId);
                logger.info("调用接口取消下单时发放的优惠券：入参：{} 出参：{}", orderId, JSON.toJSONString(coupResponseDTO));

                // 设置已经取消过 redis存放规避主从同步问题
                String redisKey = String.format(RedisKeyConsts.ORDER_CANCELED_REFUND_KEY, orderId);
                redisManager.setex(redisKey, "canceled", 60 * 60);

                // 取消创建新单
                this.createNewOrder(dbOrderWork, orderDetail, zsCancelDTO);

                if (Objects.equals(OrderConsts.ORDER_TYPE_NEW, dbOrderWork.getType()) && NumberUtil.isNotNullOrZero(dbOrderWork.getManageCompanyId())) {
                    // 预约时间当日 到 当日+14天内，发送库存预警队列
                    if (TimeUtils.isCurDateRange(dbOrderWork.getDutyTime(), 14)) {
                        PerfStockWarningDTO perfStockWarningDTO = PerfStockWarningDTO.builder()
                                .dutyDate(DateUtil.dateFormatToString(dbOrderWork.getDutyTime(), DateUtil.FORMAT_DEFAULT))
                                .cityId(dbOrderWork.getCityId())
                                .manageCompanyId(dbOrderWork.getManageCompanyId())
                                .servCategId(dbOrderWork.getServCategId())
                                .showCategOneId(dbOrderWork.getShowCategOneId())
                                .showCategTwoId(dbOrderWork.getShowCategId())
                                .build();
                        logger.info("取消-发送PERF库存预警队列[{}]", perfStockWarningDTO);
                        String perfStockWarningJson = JSON.toJSONString(perfStockWarningDTO);
                        String perfKey = String.valueOf(zsCancelDTO.getWorkId());
                        zmnMQSender.send(MessageQueueTopicConstant.ZMN_TOPIC_PERF, MessageQueueTagConsts.ZMN_PERF_STOCK_WARNING, perfKey, perfStockWarningJson);
                    }
                }

                // 重复和测试的取消不发送到ERP
                boolean duplicateOrTestReason = Objects.equals(updateOrderWork.getDuplicate(), GlobalConsts.YES)
                        || Optional.ofNullable(zsCancelDTO.getDetailDTOList()).orElse(Collections.emptyList()).stream().anyMatch(e -> Objects.equals(e.getMapId(), OrderConsts.CANCEL_TEST_ID));
                // 发送队列到ERP，收取维护费
                if (!duplicateOrTestReason && Objects.equals(OrderConsts.ORDER_TYPE_NEW, dbOrderWork.getType())
                        && NumberUtil.isNotNullOrZero(dbOrderWork.getManageCompanyId())) {
                    ErpCancelDTO erpCancelDTO = ErpCancelDTO.builder()
                            .platWork(dbOrderWork.getPlatWork())
                            .orderId(dbOrderWork.getOrderId())
                            .manageCompanyId(dbOrderWork.getManageCompanyId())
                            .bizType(dbOrderWork.getBizType())
                            .operator(zsCancelDTO.getOperator())
                            .build();
                    logger.info("取消-发送ERP队列[{}]", erpCancelDTO);
                    String json = JSON.toJSONString(erpCancelDTO);
                    String key = String.valueOf(zsCancelDTO.getWorkId());
                    zmnMQSender.send(MessageQueueTopicConstant.ZMN_TOPIC_ERP, MessageQueueTagConsts.ZMN_ERP_TAG_OTHER_FEE, key, json);
                }

                // 发送队列到SCM，退回配件
                ScmBackPartDTO dio = new ScmBackPartDTO();
                dio.setSourceId(String.valueOf(dbOrderWork.getOrderId()));
                dio.setWorkId(dbOrderWork.getWorkId());
                dio.setPlat(dbOrderWork.getPlatWork());
                dio.setStatus(GlobalConsts.NO);
                dio.setType(GlobalConsts.YES);
                dio.setGoodsTypes(OrderConsts.PART_TYPE_SOURCING_IN);
                dio.setOperator(Optional.ofNullable(zsCancelDTO.getOperator()).orElse("系统"));
                dio.setOperatorId(Optional.ofNullable(zsCancelDTO.getOperatorId()).orElse(1L));
                String key = String.valueOf(dbOrderWork.getOrderId());
                String message = JSON.toJSONString(dio);
                logger.info("取消-发送SCM,队列key:{},message{}", key, message);
                zmnMQSender.send(MessageQueueTopicConstant.ZMN_TOPIC_SCM2, OmsMqTagConsts.SCM_BACK_PARTS_TAG, key, message);

                // 退款 （仅当工单有已支付的金额，方才需要全额退款；若：工单无已支付的金额，则无退款环节）
                // 存在渠道预付不走退款逻辑
                this.sendRefund(dbOrderWork, zsCancelDTO);
            }
        } catch (Exception e) {
            logger.error("{}订单取消失败：{}", zsCancelDTO.getWorkId(), e);
            throw e;
        } finally {
            lock.unlock();
        }
    }

    /**
     * 创建新单
     * @param orderWork
     * @param orderDetail
     */
    private void createNewOrder(OrderWork orderWork, OrderDetail orderDetail, ZsCancelDTO zsCancelDTO) throws OmsBaseException {

        // 不是创建新单返回
        if (!Objects.equals(zsCancelDTO.getCreateNewOrder(), com.zmn.consts.GlobalConsts.YES)) {
            return;
        }

        List<OrderProduct> orderProductList = orderProductService.listOrderProductByOrderId(orderWork.getOrderId());

        // 操作人信息
        NormalOrderAddDIO normalOrderAddDIO = new NormalOrderAddDIO();
        normalOrderAddDIO.setServCategId(orderWork.getServCategId());
        normalOrderAddDIO.setRemark(orderWork.getCurrentRemark());
        normalOrderAddDIO.setOperator(zsCancelDTO.getOperator());
        normalOrderAddDIO.setOperatorType(Optional.ofNullable(zsCancelDTO.getOperatorType()).orElse(com.zmn.consts.GlobalConsts.OPERATE_USER_TYPE_STAFF));
        normalOrderAddDIO.setOperatorId(Optional.ofNullable(zsCancelDTO.getOperatorId()).orElse(1L));
        normalOrderAddDIO.setOperatorIP(zsCancelDTO.getIp());
        normalOrderAddDIO.setUserAgent(zsCancelDTO.getUserAgent());

        // 基础信息
        OrderBaseInfo orderBaseInfo = new OrderBaseInfo();
        orderBaseInfo.setPlat(orderWork.getPlatWork());
        orderBaseInfo.setPlatWork(orderWork.getPlatWork());
        orderBaseInfo.setBizType(orderWork.getBizType());
        orderBaseInfo.setChannelId(orderWork.getChannelId());
        orderBaseInfo.setSourceChannelId(orderWork.getSourceChannelId());
        orderBaseInfo.setReceiveEntranceId(GateTypeConsts.GATE_PLAT_BACKSTAGE);
        orderBaseInfo.setInputType(OrderConsts.ORDER_INPUT_TYPE_MANUAL);
        orderBaseInfo.setReceiverManner(OrderConsts.RECEIVE_MANNER_MANUAL);
        orderBaseInfo.setGridCompanyId(CompanyConsts.ZMN_JXJ_COMPANY_ID);
        orderBaseInfo.setGridManageCompanyId(CompanyConsts.ZMN_JXJ_INFO_MANAGE_COMPANY_ID);
        orderBaseInfo.setType(OrderConsts.ORDER_TYPE_NEW);
        orderBaseInfo.setOrderTagIds(Lists.newArrayList(OrderTagConsts.TAG_ID_NEW_ORDER_FOR_CANCEL));
        normalOrderAddDIO.setOrderBaseInfo(orderBaseInfo);

        // 用户信息
        UserDIO userDIO = new UserDIO();
        userDIO.setUserName(orderDetail.getUserName());
        userDIO.setContactName(orderDetail.getContactName());
        userDIO.setTelephone(orderDetail.getTelephone());
        userDIO.setTelephone2(orderDetail.getTelephone2());
        userDIO.setTelephone3(orderDetail.getTelephone3());
        userDIO.setGender(orderDetail.getGender());
        userDIO.setCityId(orderWork.getCityId());
        userDIO.setCountyId(orderDetail.getCountyId());
        userDIO.setStreetSource(orderDetail.getStreetSource());
        userDIO.setStreetId(orderDetail.getStreetId());
        userDIO.setStreet(orderDetail.getStreet());
        userDIO.setAddress(orderDetail.getAddress());
        userDIO.setLongitude(orderDetail.getLongitude());
        userDIO.setLatitude(orderDetail.getLatitude());
        normalOrderAddDIO.setUserDIO(userDIO);

        // 产品信息
        List<OrderProductDIO> orderProductDIOList = Lists.newArrayListWithCapacity(1);
        OrderProductDIO orderProductAddDIO = new OrderProductDIO();
        OrderProduct orderProduct = orderProductList.get(0);
        // 预约时间为当前时间➕1小时
        orderProductAddDIO.setDutyTime(DateUtil.addMinute(DateUtil.getNow(), 60));
        orderProductAddDIO.setBrandId(orderProduct.getBrandId());
        orderProductAddDIO.setTariffId(orderProduct.getTariffId());
        orderProductAddDIO.setServCategId(orderWork.getServCategId());
        orderProductAddDIO.setCategId(orderWork.getCategId());
        orderProductAddDIO.setProductId(orderProduct.getProductId());
        orderProductAddDIO.setShowProductId(orderProduct.getShowProductId());
        orderProductAddDIO.setNumber(orderProduct.getNumber());
        orderProductAddDIO.setRemark(orderProduct.getRemark());
        orderProductAddDIO.setFault(orderProduct.getFault());
        orderProductDIOList.add(orderProductAddDIO);
        normalOrderAddDIO.setOrderProductList(orderProductDIOList);

        logger.info("普通单#normalOrderRemoteService#addOrder入参：[{}]", JSON.toJSONString(normalOrderAddDIO));
        ResponseDTO<OrderAddDRO> responseDTO = normalOrderRemoteService.addOrder(normalOrderAddDIO);
        logger.info("普通单#normalOrderRemoteService#addOrder出参：[{}]", JSON.toJSONString(responseDTO));
        if (!responseDTO.isSuccess()) {
            throw new OmsBaseException("创建新单失败");
        }
    }

    /**
     * 用户端取消缘由映射
     * @param zsCancelDTO
     */
    private void userReasonMapping(ZsCancelDTO zsCancelDTO) {
        // 处理用户端取消缘由映射
        if (!Objects.equals(zsCancelDTO.getOperatorType(), GlobalConsts.OPERATE_USER_TYPE_USER)
                || CollectionUtil.isNullOrEmpty(zsCancelDTO.getDetailDTOList())) {
            return;
        }
        // 查询映射关系
        List<TagsDRO> baseCodeMapList = baseCodeService.listBaseCodeMap(GlobalConsts.PLAT_MARK_ZMN, OrderConsts.BASE_CODE_MAP_ONE_TYPE_USER_CANCEL_MAPPING, null, null);
        if (CollectionUtil.isNullOrEmpty(baseCodeMapList)) {
            return;
        }
        Map<Integer, Integer> baseCodeMap = baseCodeMapList.stream().collect(Collectors.toMap(TagsDRO::getTwoTypeId, TagsDRO::getThreeTypeId));
        // 查询取消缘由
        OrderCancelReasonQuery orderCancelReasonQuery = new OrderCancelReasonQuery();
        orderCancelReasonQuery.setStatus(GlobalConsts.YES);
        List<OrderCancelReasonVO> orderCancelReasonVOList = orderCancelReasonService.listByQuery(orderCancelReasonQuery);
        if (CollectionUtil.isNullOrEmpty(orderCancelReasonVOList)) {
            return;
        }
        Map<Integer, String> cancelMap = orderCancelReasonVOList.stream().collect(Collectors.toMap(OrderCancelReasonVO::getId, OrderCancelReasonVO::getReason));
        List<OrderRemarkDetailDTO> detailDTOList = Lists.newArrayListWithCapacity(zsCancelDTO.getDetailDTOList().size());
        zsCancelDTO.getDetailDTOList().forEach(e -> {
            OrderRemarkDetailDTO dto = new OrderRemarkDetailDTO();
            Integer reasonId = baseCodeMap.get(e.getMapId());
            if (Objects.isNull(reasonId)) {
                dto.setMapId(e.getMapId());
                dto.setMapName(e.getMapName());
                detailDTOList.add(dto);
                return;
            }
            String reason = cancelMap.get(reasonId);
            if (StringUtil.isBlank(reason)) {
                dto.setMapId(e.getMapId());
                dto.setMapName(e.getMapName());
                detailDTOList.add(dto);
                return;
            }
            dto.setMapId(reasonId);
            dto.setMapName(reason);
            detailDTOList.add(dto);
        });
        zsCancelDTO.setDetailDTOList(detailDTOList);
    }

    /**
     * 取消申请
     */
    @Deprecated
    @Override
    public void saveCancelApply(CancelApplyDTO cancelApplyDTO) throws OmsBaseException {
        OrderRemarkDetailDTO orderRemarkDetailDTO = cancelApplyDTO.getDetailDTOList().get(0);

        // 生成跟单数据
        TrackWorkDIO trackDIO = new TrackWorkDIO();
        trackDIO.setOrderId(cancelApplyDTO.getOrderId());
        trackDIO.setWorkId(cancelApplyDTO.getWorkId());
        trackDIO.setTrackContentId(TrackConfigConsts.TRACK_CONTENT_ID_USER_CANCEL);
        trackDIO.setReasonId(orderRemarkDetailDTO.getMapId());
        trackDIO.setReasonName(orderRemarkDetailDTO.getMapName());

        StringJoiner stringJoiner = new StringJoiner("；");
        if (StringUtils.isNotBlank(cancelApplyDTO.getRemark())) {
            stringJoiner.add(cancelApplyDTO.getRemark());
        }
        if (Objects.equals(90, cancelApplyDTO.getEntranceId())) {
            stringJoiner.add("用户短信取消");
        }
        if (stringJoiner.length() > 0) {
            trackDIO.setOperatorLogRemark(stringJoiner.toString());
        }
//        trackDIO.setOperatorLogRemark(String.format("取消缘由：%s",
//                StringUtils.join(cancelApplyDTO.getDetailDTOList().stream().map(OrderRemarkDetailDTO::getMapName).collect(Collectors.toList()), ";")));
//        if (stringJoiner.length() > 0) {
//            trackDIO.setOperatorLogRemark(StringUtils.join(Arrays.asList(trackDIO.getOperatorLogRemark(), "用户短信取消"), ";"));
//        }
        OrderWork orderWork = orderWorkService.findOrderWorkByKey(cancelApplyDTO.getOrderId(), cancelApplyDTO.getWorkId());
        if (NumberUtil.isNullOrZero(orderWork.getDepositAmount())) {
            trackDIO.setRemark("10分钟内，请勿人工处理");
        }

        // 操作人信息
        trackDIO.setOperator(cancelApplyDTO.getOperator());
        trackDIO.setOperatorId(cancelApplyDTO.getOperatorId());
        trackDIO.setOperatorType(cancelApplyDTO.getOperatorType());
        ResponseDTO responseDTO = trackWorkModifyRemoteService.addTrack(trackDIO);

        // 订单检查，工程师师傅操作 同意 或 不同意取消
        if (Objects.equals(orderWork.getPlatWork(), com.zmn.consts.GlobalConsts.PLAT_MARK_ZMN) &&
                NumberUtil.isNullOrZero(orderWork.getDepositAmount()) &&
                (Objects.equals(orderWork.getStatus(), OrderStatusConsts.WORK_STATUS_TAKE) ||
                        Objects.equals(orderWork.getStatus(), OrderStatusConsts.WORK_STATUS_VISIT))) {
            try {
                this.addEngineerReviewCancelCheck(cancelApplyDTO);
            } catch (Exception e) {
                e.printStackTrace();
                throw new OmsBaseException(e.getMessage());
            }
        }
        if (!responseDTO.isSuccess()) {
            throw new OmsBaseException(responseDTO.getMessage());
        }
    }

    /**
     * 发起工程师取消检查
     */
    private void addEngineerReviewCancelCheck(CancelApplyDTO cancelApplyDTO) {
        logger.info("发起工程师审核取消延时检查[{}]", cancelApplyDTO);
        TagsDRO oneBaseCodeMap = baseCodeService.getOneBaseCodeMap(com.zmn.consts.GlobalConsts.PLAT_MARK_ZMN, TagConsts.TAG_ONE_TYPE_NUMBER_AUTO_CANCEL_TIME, null);
        Integer autoCancelTime = oneBaseCodeMap.getTwoTypeId();
        if (Objects.isNull(autoCancelTime)) {
            logger.error("发起工程师审核取消延时检查[{}]失败,原因：获取自动取消时间失败", cancelApplyDTO.getOrderId());
            return;
        }
        String keyMQ = "mos_engineer_cancel_check_" + cancelApplyDTO.getOrderId();
        String message = JSON.toJSONString(cancelApplyDTO);
        zmnMQSender.sendWithStartDeliverTime(MqTopicConsts.ZMN_TOPIC_OMS, OmsMqTagConsts.ZMN_TOPIC_OMS_ENGINEER_REVIEW_CANCEL_CHECK, keyMQ, message, System.currentTimeMillis() + (autoCancelTime * 60000));
    }

    /**
     * 取消多次上门
     * @param zsCancelDTO
     */
    private void cancelMultipleVisit(ZsCancelDTO zsCancelDTO) {
        List<OrderVisit> orderVisitList = orderVisitService.listByOrderId(zsCancelDTO.getOrderId());
        orderVisitList.forEach(visit -> {
            // 已提交/已出发可以取消
            if (Objects.equals(visit.getVisitStatus(), OrderVisitStatusConsts.ORDER_VISIT_STATUS_CANCEL)
                    || Objects.equals(visit.getVisitStatus(), OrderVisitStatusConsts.ORDER_VISIT_STATUS_VISIT)) {
                return;
            }
            if (NumberUtil.isNullOrZero(visit.getOrderPayId())) {
                if (Objects.equals(visit.getAcceptanceResultStatus(), OrderConsts.ORDER_ACCEPTANCE_STATUS_SUCCESS)
                        || Objects.equals(visit.getAcceptanceResultStatus(), OrderConsts.ORDER_ACCEPTANCE_STATUS_NON)
                        || NumberUtil.isNullOrZero(visit.getAcceptanceId())) {
                    return;
                }
            }
            OrderMultipleVisitDTO dto = BeanMapper.map(zsCancelDTO, OrderMultipleVisitDTO.class);
            dto.setVisitId(visit.getVisitId());
            dto.setOperateTime(new Date(zsCancelDTO.getOperateTime().getTime() + 1));
            try {
                orderWorkMultipleVisitBService.cancelAgainVisit(dto);
            } catch (OmsBaseException e) {
                logger.error("取消再次上门子状态失败：" + e.getMessage());
            }
        });
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @ZsNormalOrderWorkLog(type = OrderLogConsts.ORDER_LOG_TYPE_CANCEL)
    public void saveUnCancel(ZsCancelDTO zsCancelDTO) {
        // 审核失败保存日志
        orderRemarkBService.insertOrderRemark(zsCancelDTO, OrderConsts.ORDER_REMARK_TYPE_CANCEL);

        if (Objects.nonNull(zsCancelDTO.getReviewStatus())) {
            // 更新审核状态
            OrderWork upOrderWork = new OrderWork();
            upOrderWork.setOrderId(zsCancelDTO.getOrderId());
            upOrderWork.setWorkId(zsCancelDTO.getWorkId());
            upOrderWork.setRefundReviewStatus(zsCancelDTO.getReviewStatus());
            orderWorkAmountService.updateRefund(upOrderWork);
            // 更新masterWorking.waitCancel
            masterWorkingService.updateMasterWorkingStatus(zsCancelDTO.getWorkId(), null, null, GlobalConsts.NO);
        }
    }

    /**
     * 退款列表
     *
     * @param orderWork
     * @return
     */
    @Override
    public List<RefundAmountVO> getRefundList(OrderWork orderWork) {
        List<RefundAmountVO> list = Lists.newArrayList();

        List<OrderPay> orderPays = orderPayService.listOrderPayByOrderId(orderWork.getOrderId());
        List<OrderPay> refundOrderPays = orderPays.stream()
                .filter(e -> Objects.equals(e.getTradeType(), PayConsts.PAY_TRADE_TYPE_REFUND))
                .collect(Collectors.toList());
        if (CollectionUtil.isNotNullOrEmpty(refundOrderPays)) {
            for (OrderPay obj : refundOrderPays) {
                RefundAmountVO refundAmountVO = new RefundAmountVO();
                refundAmountVO.setAmountType(obj.getAmountType());
                refundAmountVO.setAmountTypeName(OrderPayConsts.getAmountTypeName(obj.getAmountType()));
                refundAmountVO.setPayChannelName(PayConsts.getPayChannelName(obj.getPayChannelId()));
                refundAmountVO.setRefundStatus(obj.getPayStatus());
                refundAmountVO.setRefundStatusName(PayConsts.getPayStatusName(obj.getPayStatus()));
                refundAmountVO.setAmount(obj.getAmount());
                refundAmountVO.setType(obj.getRefundType());
                list.add(refundAmountVO);
            }
            return list;
        }

        // 渠道预付已支付 增加付款记录
        if (Objects.nonNull(orderWork.getChannelPrepayAmount()) && Objects.equals(orderWork.getChannelPrepayStatus(), PayConsts.PAY_STATUS_DONE)) {
            RefundAmountVO refundAmountVO = new RefundAmountVO();
            refundAmountVO.setAmountTypeName(OrderPayConsts.getAmountTypeName(OrderPayConsts.ORDER_PAY_CHANNEL_PREPAY));
            refundAmountVO.setAmount(orderWork.getChannelPrepayAmount());
            refundAmountVO.setPayChannelName(PayConsts.getPayChannelName(PayConsts.PAY_CHANNEL_PLATFORM_CHANNEL));
            refundAmountVO.setType(1);
            list.add(refundAmountVO);
        }

        // 取工单支付凭证
		List<OrderPay> orderPayList = orderPays.stream()
				.filter(e -> Objects.equals(e.getTradeType(), PayConsts.PAY_TRADE_TYPE_INTIME))
				.collect(Collectors.toList());

        List<Integer> orderAmountItem = Arrays.asList(OrderPayConsts.ORDER_PAY_MASTER, OrderPayConsts.ORDER_PAY_PREPAY, OrderPayConsts.ORDER_PAY_DEPOSIT);
        List<OrderPay> payVoucherOrder = orderPays.stream()
                .filter(e -> Objects.equals(e.getTradeType(), PayConsts.PAY_TRADE_TYPE_INTIME)
                        && orderAmountItem.contains(e.getAmountType()))
                .collect(Collectors.toList());

        for (OrderPay obj : payVoucherOrder) {
            RefundAmountVO refundAmountVO = new RefundAmountVO();
            refundAmountVO.setAmountType(obj.getAmountType());
            refundAmountVO.setType(1);// 非现金
            refundAmountVO.setAmountTypeName(OrderPayConsts.getAmountTypeName(obj.getAmountType()));
            refundAmountVO.setAmount(obj.getAmount());
            refundAmountVO.setAlreadyRefundAmount(0);
            refundAmountVO.setPayChannelName(PayConsts.getPayChannelName(obj.getPayChannelId()));
            refundAmountVO.setRefundStatus(PayConsts.PAY_STATUS_DONE);
            refundAmountVO.setRefundStatusName(PayConsts.getPayStatusName(PayConsts.PAY_STATUS_DONE));
            list.add(refundAmountVO);
        }
        return list;

    }

    /**
     * 执行退款
     *
     * @param dbOrderWork
     * @return
     */
    private void sendRefund(OrderWork dbOrderWork, ZsCancelDTO zsCancelDTO) throws OmsBaseException {
        // 秦一峰那边已经执行过退款，所以在工单这边跳过
        if (CONTINUE_CANCEL_REFUNND_ORDER_ID.contains(zsCancelDTO.getOrderId())) {
            return;
        }
        // 退款 （仅当工单有已支付的金额，方才需要全额退款；若：工单无已支付的金额，则无退款环节）
        boolean masterAmountStatus = NumberUtil.isNotNullOrZero(dbOrderWork.getMasterAmount()) && Objects.equals(dbOrderWork.getMasterPayStatus(), PayConsts.PAY_STATUS_DONE);
        boolean prepayAmountStatus = NumberUtil.isNotNullOrZero(dbOrderWork.getPrepayAmount()) && Objects.equals(dbOrderWork.getPrepayStatus(), PayConsts.PAY_STATUS_DONE);
        boolean depositAmountStatus = NumberUtil.isNotNullOrZero(dbOrderWork.getDepositAmount()) && Objects.equals(dbOrderWork.getDepositStatus(), PayConsts.PAY_STATUS_DONE);
        boolean channelPrepayAmountStatus = NumberUtil.isNotNullOrZero(dbOrderWork.getChannelPrepayAmount()) && Objects.equals(dbOrderWork.getChannelPrepayStatus(), PayConsts.PAY_STATUS_DONE);
        if (masterAmountStatus || prepayAmountStatus || depositAmountStatus || channelPrepayAmountStatus) {
            Integer masterAmount = masterAmountStatus ? dbOrderWork.getMasterAmount() : 0;
            Integer prepayAmount = prepayAmountStatus ? dbOrderWork.getPrepayAmount() : 0;
            Integer channelPrepayAmount = channelPrepayAmountStatus ? dbOrderWork.getChannelPrepayAmount() : 0;
            Integer depositAmount = depositAmountStatus ? dbOrderWork.getDepositAmount() : 0;
            Integer totalAmount = masterAmount + prepayAmount + depositAmount + channelPrepayAmount;
            OmsOperator operator = new OmsOperator();
            operator.setOperatorPlat(zsCancelDTO.getOperatorPlat());
            operator.setOperatorType(zsCancelDTO.getOperatorType());
            operator.setOperatorId(zsCancelDTO.getOperatorId());
            operator.setOperator(zsCancelDTO.getOperator());
            Integer refundType = null;
            if (NumberUtil.isNotNullOrZero(channelPrepayAmount)) {
                refundType = OrderConsts.ORDER_REFUND_TYPE_OFFLINE;
            } else {
                refundType = OrderConsts.ORDER_REFUND_TYPE_ONLINE;
            }
            List<OrderPay> orderPayList = orderPayBService.listOrderPayByOrderId(dbOrderWork.getOrderId());

            RefundInitiateBO refundInitiateBO = RefundInitiateBO.builder()
                    .refundInitiateType(RefundInitiateTypeEnum.CANCEL_REFUND.getType())
                    .refundType(refundType)
                    .refundAmount(totalAmount)
                    .refundOrderWork(dbOrderWork)
                    .orderPayList(orderPayList)
                    .operator(operator)
                    .build();
            com.zmn.pay.gateway.common.model.dro.RefundDRO refundDRO = zsOrderPayBService.payRefundAmount(refundInitiateBO);
            logger.info("{}取消退款-请求{},返回{}", dbOrderWork.getWorkId(), refundInitiateBO, JSON.toJSONString(refundDRO));
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @ZsNormalOrderWorkLog(type = OrderLogConsts.ORDER_LOG_TYPE_REFUND, beforeProceed = false)
    public OrderWork insertRefundOrderWork(ZsNormalRefundWorkDTO refundWorkDTO) throws Exception {
        OrderWork refundOrderWork = new OrderWork();
        refundOrderWork.setType(OrderConsts.ORDER_TYPE_REFUND);

        // 订单处理
        Order order = orderService.findOrderByKey(refundWorkDTO.getOrderId());
        OrderDetail orderDetail = orderDetailService.findOrderDetailByKey(refundWorkDTO.getOrderId());
        OrderWork orderWork = orderWorkService.findOrderWorkByKey(refundWorkDTO.getOrderId(), refundWorkDTO.getWorkId());

        // 渠道：塞退款源单所在服务平台下的工程师推荐渠道（啄木鸟：1585，言而有信：32806，一步维修：32808，川南环保：31042）
//        Integer refundChannelId = ChannelConsts.getRefundChannelId(orderWork.getPlatWork());
//        logger.debug("退款渠道[{}]", refundChannelId);
//        refundOrderWork.setSourceChannelId(refundChannelId);
//        refundOrderWork.setChannelId(refundChannelId);
        // 退款单 使用原单渠道
        refundOrderWork.setChannelId(orderWork.getChannelId());
        refundOrderWork.setSourceChannelId(orderWork.getSourceChannelId());

        OrderDTO orderDTO = new OrderDTO();
        orderDTO.setOrderWork(refundOrderWork);
        orderDTO.setOrder(order);
        orderDTO.setOrderDetail(orderDetail);
        orderDTO.setDbOrderWork(orderWork);
        orderWorkBService.processOrderWork(orderDTO);

        // 退款参数
        BeanMapper.copy(refundWorkDTO, refundOrderWork);

        // 保存工单
        Date now = DateUtil.getNow();
        refundOrderWork.setWorkId(null);
        refundOrderWork.setPlat(orderWork.getPlat());
        refundOrderWork.setPlatWork(orderWork.getPlatWork());
        refundOrderWork.setBizType(orderWork.getBizType());

        // 退款原单号
        if (NumberUtil.isNullOrZero(orderWork.getOriginalId())
                || Objects.equals(orderWork.getType(), OrderConsts.ORDER_TYPE_NEW)) {
            refundOrderWork.setOriginalId(refundWorkDTO.getWorkId());
        } else {
            refundOrderWork.setOriginalId(orderWork.getOriginalId());
        }

        if (NumberUtil.isNullOrZero(refundWorkDTO.getRefundWorkId())) {
            refundOrderWork.setRefundWorkId(orderWork.getWorkId());
        } else {
            refundOrderWork.setRefundWorkId(refundWorkDTO.getRefundWorkId());
        }
        refundOrderWork.setTotalAmount(Optional.ofNullable(refundWorkDTO.getRefundAmount()).orElse(0) * -1);
        refundOrderWork.setOriginalAmount(Optional.ofNullable(refundWorkDTO.getRefundAmount()).orElse(0) * -1);
        refundOrderWork.setDiscountPrepayAmount(Optional.ofNullable(refundWorkDTO.getRefundDTO().getDiscountRefundAmount()).orElse(0) * -1);
        // 退款单设置为普通单
        refundOrderWork.setManageCompanyId(refundWorkDTO.getManageCompanyId());
        refundOrderWork.setManageCompanyName(refundWorkDTO.getManageCompanyName());
        refundOrderWork.setManageCompanyType(refundWorkDTO.getManageCompanyType());

        // 冗余服务商三级类型
        ResponseDTO<SpServProviderDRO> remoteSp = spManageListRemoteService.getServProviderById(refundWorkDTO.getManageCompanyId());
        refundOrderWork.setManageCompanyThirdType(remoteSp.getData().getThirdType());
        refundOrderWork.setOrgFourId(refundWorkDTO.getManageCompanyId());
        refundOrderWork.setBizMode(refundWorkDTO.getBizMode());
        refundOrderWork.setSourceType(OrderConsts.ORDER_SOURCE_TYPE_NORMAL);
        refundOrderWork.setPayStatus(PayConsts.REFUND_STATUS_ING);
        refundOrderWork.setRefundTime(now);
        refundOrderWork.setPayTime(now);
//        refundOrderWork.setCompleteTime(now);
//        refundOrderWork.setCompleterId(refundWorkDTO.getOperatorId());
        refundOrderWork.setCreateTime(now);
        refundOrderWork.setReceiveTime(now);
        refundOrderWork.setDutyTime(now);
        refundOrderWork.setReceiverId(refundWorkDTO.getOperatorId());
        refundOrderWork.setReceiverType(refundWorkDTO.getOperatorType());
        refundOrderWork.setCreater(refundWorkDTO.getOperator());
        refundOrderWork.setCurrentRemark(refundWorkDTO.getOperatorRemark());
        refundOrderWork.setAssignConfirmTime(now);
        refundOrderWork.setShowServCategName(orderWork.getShowServCategName());
        refundOrderWork.setShowCategOneId(orderWork.getShowCategOneId());
        refundOrderWork.setShowCategId(orderWork.getShowCategId());
        refundOrderWork.setShowProductId(orderWork.getShowProductId());
        refundOrderWork.setServProductGroupId(orderWork.getServProductGroupId());
        refundOrderWork.setServProductGroupName(orderWork.getServProductGroupName());
        refundOrderWork.setMasterSupervisorId(orderWork.getMasterSupervisorId());
        refundOrderWork.setMasterSupervisorName(orderWork.getMasterSupervisorName());
        refundOrderWork.setMasterSupervisorPhone(orderWork.getMasterSupervisorPhone());
        refundOrderWork.setReceiveEntranceId(orderWork.getReceiveEntranceId());
        refundOrderWork.setReceiveEntranceType(orderWork.getReceiveEntranceType());

        // 业务线
        refundOrderWork.setServProductGroupId(orderWork.getServProductGroupId());
        refundOrderWork.setServProductGroupName(orderWork.getServProductGroupName());
        refundOrderWork.setBizLine(orderWork.getBizLine());

        orderWorkBService.insertOrderWork(refundOrderWork);

        // 修改原单信息
        OrderWork updateOrderWork = new OrderWork();
        updateOrderWork.setOrderId(orderWork.getOrderId());
        updateOrderWork.setWorkId(orderWork.getWorkId());
        updateOrderWork.setRefundTargetWorkId(refundOrderWork.getWorkId());
        orderWorkService.updateOrderWorkByKey(updateOrderWork);

        // 保存工程师
        OrderMaster orderMaster = new OrderMaster();
        orderMaster.setOrderId(refundOrderWork.getOrderId());
        orderMaster.setWorkId(refundOrderWork.getWorkId());
        orderMaster.setMasterId(refundWorkDTO.getMasterId());
        orderMaster.setType(OrderConsts.ORDER_MASTER_TYPE_MAIN);
        orderMaster.setCreater(refundWorkDTO.getOperator());
        orderMaster.setCreateTime(now);
        orderMaster.setStarLevel(GlobalConsts.NONE);
        orderMasterBService.insertOrderMaster(orderMaster);

        // 如果原单是多工程师，处理多工程师信息
        if (CollectionUtil.isNotNullOrEmpty(refundWorkDTO.getMasterList())) {
            MultiMasterDTO multiMasterDTO = BeanMapper.map(refundWorkDTO, MultiMasterDTO.class);
            multiMasterDTO.setOrderId(refundOrderWork.getOrderId());
            multiMasterDTO.setWorkId(refundOrderWork.getWorkId());
            zsCustomWorkBService.saveMultiMasterNoLog(multiMasterDTO);
        }

        // 保存退款缘由
        OrderRemarkDTO orderRemarkDTO = new OrderRemarkDTO();
        orderRemarkDTO.setOrderId(refundWorkDTO.getOrderId());
        orderRemarkDTO.setWorkId(refundOrderWork.getWorkId());
        orderRemarkDTO.setOperatorId(refundWorkDTO.getOperatorId());
        orderRemarkDTO.setOperatorType(refundWorkDTO.getOperatorType());
        orderRemarkDTO.setContent(refundWorkDTO.getOperatorRemark());

        // 退款原因选项
        if (Objects.nonNull(refundWorkDTO.getReasonIdList())) {
            List<OrderRemarkDetailDTO> orderRemarkDetailList = Lists.newArrayListWithExpectedSize(refundWorkDTO.getReasonIdList().size());
            for (int i = refundWorkDTO.getReasonIdList().size() - 1; i >= 0; i--) {
                orderRemarkDetailList.add(new OrderRemarkDetailDTO(refundWorkDTO.getReasonIdList().get(i), refundWorkDTO.getReasonNameList().get(i), null, 0));
            }
            orderRemarkDTO.setDetailDTOList(orderRemarkDetailList);
        }
        orderRemarkBService.insertOrderRemark(orderRemarkDTO, OrderConsts.ORDER_REMARK_TYPE_REFUND);

        // 设置新的工单ID
        refundWorkDTO.setWorkId(refundOrderWork.getWorkId());

        // 退款日志
        refundWorkDTO.setOperatorLogRemark(String.format("退款单退款-退款缘由：%s；%s", StringUtils.join(Optional.ofNullable(refundWorkDTO.getReasonNameList()).orElse(Lists.newArrayList()), "；"), refundWorkDTO.getOperatorRemark()));

        // 2022/04/02 新建退款单时 不修改保修时间 在退款成功时 修改保修卡状态
        // 设置保修过期时间为当前
//        List<OrderWarrantyProduct> warrantyProducts = orderWarrantyProductService.listByOrderId(refundWorkDTO.getOrderId());
//        if (CollectionUtil.isNotNullOrEmpty(warrantyProducts)) {
//            if (NumberUtil.isNullOrZero(orderWork.getRefundTargetWorkId())) {
//                OrderWarrantyProduct warrantyProduct = new OrderWarrantyProduct();
//                warrantyProduct.setExpiredTime(new Date());
//                warrantyProduct.setWarrId(refundWorkDTO.getOrderId());
//                orderWarrantyProductService.updateExpiredTime(warrantyProduct);
//            }
//        }
        // 如果退款单需要审批则发起审批
        if (refundWorkDTO.isRefundReview()) {
            omsOrderReviewBService.initiateRefundReview(refundOrderWork, refundWorkDTO.getRefundDTO());
        }
        return refundOrderWork;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @ZsNormalOrderWorkLog(type = OrderLogConsts.ORDER_LOG_TYPE_COMPENSATE, beforeProceed = false)
    public OrderWork insertCompensateOrderWork(ZsNormalCompensateWorkDTO compensateWorkDTO) throws OmsBaseException {
        OrderWork compensateOrderWork = new OrderWork();
        compensateOrderWork.setType(OrderConsts.ORDER_TYPE_COMPENSATE);

        // 订单处理
        Order order = orderService.findOrderByKey(compensateWorkDTO.getOrderId());
        OrderDetail orderDetail = orderDetailService.findOrderDetailByKey(compensateWorkDTO.getOrderId());
        OrderWork orderWork = orderWorkService.findOrderWorkByKey(compensateWorkDTO.getOrderId(), compensateWorkDTO.getWorkId());

        // 赔偿单渠道
        compensateOrderWork.setSourceChannelId(orderWork.getSourceChannelId());
        compensateOrderWork.setChannelId(orderWork.getChannelId());

        OrderDTO orderDTO = new OrderDTO();
        orderDTO.setOrderWork(compensateOrderWork);
        orderDTO.setOrder(order);
        orderDTO.setOrderDetail(orderDetail);
        orderDTO.setDbOrderWork(orderWork);
        orderWorkBService.processOrderWork(orderDTO);
        // 赔偿参数
        BeanMapper.copy(compensateWorkDTO, compensateOrderWork);
        // 保存工单
        Date now = DateUtil.getNow();
        compensateOrderWork.setWorkId(null);
        compensateOrderWork.setPlat(orderWork.getPlat());
        compensateOrderWork.setPlatWork(orderWork.getPlatWork());
        compensateOrderWork.setBizType(orderWork.getBizType());
        compensateOrderWork.setOriginalId(compensateWorkDTO.getWorkId());

        compensateOrderWork.setTotalAmount(Optional.ofNullable(compensateWorkDTO.getCompensateAmount()).orElse(0) * -1);
        compensateOrderWork.setOriginalAmount(Optional.ofNullable(compensateWorkDTO.getCompensateAmount()).orElse(0) * -1);

        // 业务线
        compensateOrderWork.setServProductGroupId(orderWork.getServProductGroupId());
        compensateOrderWork.setServProductGroupName(orderWork.getServProductGroupName());
        compensateOrderWork.setBizLine(orderWork.getBizLine());

        // 赔偿单设置为普通单
        compensateOrderWork.setManageCompanyId(orderWork.getManageCompanyId());
        compensateOrderWork.setManageCompanyName(orderWork.getManageCompanyName());
        compensateOrderWork.setManageCompanyType(orderWork.getManageCompanyType());

        // 冗余服务商三级类型
        ResponseDTO<SpServProviderDRO> remoteSp = spManageListRemoteService.getServProviderById(compensateOrderWork.getManageCompanyId());
        if (Objects.nonNull(remoteSp.getData())) {
            compensateOrderWork.setManageCompanyThirdType(remoteSp.getData().getThirdType());
        }
        compensateOrderWork.setOrgFourId(compensateOrderWork.getManageCompanyId());
        compensateOrderWork.setBizMode(compensateWorkDTO.getBizMode());
        compensateOrderWork.setSourceType(OrderConsts.ORDER_SOURCE_TYPE_NORMAL);
        compensateOrderWork.setRefundTime(now);
        compensateOrderWork.setCreateTime(now);
        compensateOrderWork.setReceiveTime(now);
        compensateOrderWork.setDutyTime(now);
        compensateOrderWork.setReceiverId(compensateWorkDTO.getOperatorId());
        compensateOrderWork.setReceiverType(compensateWorkDTO.getOperatorType());
        compensateOrderWork.setCreater(compensateWorkDTO.getOperator());
        compensateOrderWork.setCurrentRemark(compensateWorkDTO.getContent());
        compensateOrderWork.setAssignConfirmTime(now);
        compensateOrderWork.setShowServCategName(orderWork.getShowServCategName());
        compensateOrderWork.setShowCategOneId(orderWork.getShowCategOneId());
        compensateOrderWork.setShowCategId(orderWork.getShowCategId());
        compensateOrderWork.setShowProductId(orderWork.getShowProductId());
        compensateOrderWork.setServProductGroupId(orderWork.getServProductGroupId());
        compensateOrderWork.setServProductGroupName(orderWork.getServProductGroupName());
        compensateOrderWork.setMasterSupervisorId(orderWork.getMasterSupervisorId());
        compensateOrderWork.setMasterSupervisorName(orderWork.getMasterSupervisorName());
        compensateOrderWork.setMasterSupervisorPhone(orderWork.getMasterSupervisorPhone());
        compensateOrderWork.setReceiveEntranceId(orderWork.getReceiveEntranceId());
        compensateOrderWork.setReceiveEntranceType(orderWork.getReceiveEntranceType());
        compensateOrderWork.setMultiMaster(orderWork.getMultiMaster());

        orderWorkBService.insertOrderWork(compensateOrderWork);

        // 复制原单工程师信息
        List<OrderMaster> masters = orderMasterService.listMasterByWorkId(orderWork.getOrderId(), orderWork.getWorkId());
        if (CollectionUtil.isNotNullOrEmpty(masters)) {
            for (OrderMaster master : masters) {
                master.setMasterOrderId(null);
                master.setOrderId(compensateWorkDTO.getOrderId());
                master.setWorkId(compensateOrderWork.getWorkId());
                master.setCreateTime(DateUtil.getNow());
                master.setCreater(compensateWorkDTO.getOperator());
                master.setUpdater(compensateWorkDTO.getOperator());
                master.setUpdateTime(DateUtil.getNow());
            }
            orderMasterService.insertAll(masters);
        }

        // 保存退款缘由
        OrderRemarkDTO orderRemarkDTO = new OrderRemarkDTO();
        orderRemarkDTO.setOrderId(compensateWorkDTO.getOrderId());
        orderRemarkDTO.setWorkId(compensateOrderWork.getWorkId());
        orderRemarkDTO.setOperatorId(compensateWorkDTO.getOperatorId());
        orderRemarkDTO.setOperatorType(compensateWorkDTO.getOperatorType());
        orderRemarkDTO.setContent(compensateWorkDTO.getContent());
        if (CollectionUtil.isNotNullOrEmpty(compensateWorkDTO.getReasonList())) {
            List<OrderRemarkDetailDTO> orderRemarkDetailList = Lists.newArrayListWithExpectedSize(compensateWorkDTO.getReasonList().size());
            for (KVDict kvDict : compensateWorkDTO.getReasonList()) {
                orderRemarkDetailList.add(new OrderRemarkDetailDTO(Integer.valueOf(kvDict.getValue().toString()), kvDict.getText(), null, 0));
            }
            orderRemarkDTO.setDetailDTOList(orderRemarkDetailList);
        }
        orderRemarkBService.insertOrderRemark(orderRemarkDTO, OrderConsts.ORDER_REMARK_TYPE_COMPENSATE);
        // 设置新的工单ID
        compensateWorkDTO.setWorkId(compensateOrderWork.getWorkId());
        return compensateOrderWork;
    }

    private void cancelPayOrder (OrderWork orderWork, OmsOperator operator) throws OmsBaseException {
        RevokeGatewayDIO revokeGatewayDIO = new RevokeGatewayDIO();
        revokeGatewayDIO.setAppBizNo(String.valueOf(orderWork.getOrderId()));
        revokeGatewayDIO.setAppId(AppEnum.APP_OMS.getAppId());
        revokeGatewayDIO.setAppName(AppEnum.APP_OMS.getAppName());
        revokeGatewayDIO.setPlat(orderWork.getPlat());
        revokeGatewayDIO.setOperator(operator.getOperator());
        revokeGatewayDIO.setOperatorId(operator.getOperatorId());
        revokeGatewayDIO.setOperatorType(operator.getOperatorType());
//        revokeGatewayDIO.setPayPlat(orderWork.getPlatWork());
        logger.info("调用支付网关，尝试取消支付中的支付订单 入参：{}", JSON.toJSONString(revokeGatewayDIO));
        ResponseDTO<Boolean> responseDTO = payGatewayRemoteService.revoke(revokeGatewayDIO);
        logger.info("调用支付网关，尝试取消支付中的支付订单 出参：{}", JSON.toJSONString(responseDTO));
        if (!responseDTO.isSuccess()) {
            throw new OmsBaseException("取消进行中的支付订单失败，请稍后重试");
        }
    }

    private void cancelVerify(ZsCancelDTO zsCancelDTO) throws OmsBaseException {

        // 强制取消不校验
        if (Objects.equals(zsCancelDTO.getAgreeCancel(), GlobalConsts.YES)) {
            return;
        }

        // 不是取消申请取消的校验
        if (!Objects.equals(zsCancelDTO.getEntranceId(), OrderWorkCancelEntranceEnum.CANCEL_APPLY.getCode())) {
            // 有待审核的取消申请不允许取消
            OrderCancelApplyQuery orderCancelApplyQuery = new OrderCancelApplyQuery();
            orderCancelApplyQuery.setOrderId(zsCancelDTO.getOrderId());
            orderCancelApplyQuery.setWorkId(zsCancelDTO.getWorkId());
            orderCancelApplyQuery.setReviewStatusList(Lists.newArrayList(CancelApplyConsts.ORDER_REVIEW_STATUS_CHECK, CancelApplyConsts.ORDER_REVIEW_STATUS_CHECK_PROCESSING));
            logger.info("{}根据条件查询取消申请#listCancelApplyByQuery query={}", zsCancelDTO.getWorkId(), orderCancelApplyQuery);
            ResponseDTO<List<OrderCancelApplyDRO>> listResponseDTO = orderCancelApplyListRemoteService.listCancelApplyByQuery(orderCancelApplyQuery);
            logger.info("{}根据条件查询取消申请#listCancelApplyByQuery listResponseDTO={}", zsCancelDTO.getWorkId(), listResponseDTO);
            if (CollectionUtil.isNotNullOrEmpty(listResponseDTO.getData())) {
                OrderCancelApplyDRO orderCancelApplyDRO = listResponseDTO.getData().get(0);
                if (Objects.equals(GlobalConsts.OPERATE_USER_TYPE_STAFF, orderCancelApplyDRO.getReviewUserType())) {
                    throw new OmsBaseException(OmsErrorCodeConsts.ERROR_ORDER_CANCEL_CHECK_REVIEW_STAFF, "存在待审核或处理中的取消申请，确定直接取消订单吗？");
                }

                if (Objects.equals(GlobalConsts.OPERATE_USER_TYPE_MASTER, orderCancelApplyDRO.getReviewUserType())) {
                    throw new OmsBaseException(OmsErrorCodeConsts.ERROR_ORDER_CANCEL_CHECK_REVIEW_MASTER, "存在需工程师审核的取消申请，确定直接取消订单吗？");
                }
            }
        }


        // 不是退款取消，校验权限
        boolean refundCancel = Objects.equals(zsCancelDTO.getRefundCancel(), GlobalConsts.YES);
        if (!refundCancel) {
            OperatePermissionVO operatePermission = zsOrderWorkOperatePermissionBService.getOperatePermission(zsCancelDTO.getOrderId(), zsCancelDTO.getWorkId(), OrderConsts.ORDER_OP_TYPE_CANCEL, zsCancelDTO.getOperatorType());
            if (!operatePermission.getCanOperate()) {
                logger.error("#order#saveCancel fail msg : {} req : {}", operatePermission.getMsg(), JSON.toJSONString(zsCancelDTO));
                throw new OmsBaseException(operatePermission.getCode(), operatePermission.getMsg());
            }
        }
    }

}
